home *** CD-ROM | disk | FTP | other *** search
- Eric Gans
- French Dep't UCLA
- Los Angeles, CA 90024
-
- LDRES.DOC v1.0
- 01/05/87
-
- It's laborious but fairly straightforward to write memory-
- resident programs in assembly language. You know the size of
- your program; you know how much memory it needs; you know where
- to enter it from your interrupt routine. All this changes for
- the worse when you work in a higher-level language. Compilers
- don't come with a "makeres" function that rearranges their code
- for this purpose. Even a language as flexible as C requires you
- to handle most of the residency process through assembly-language
- modules.
-
- LDRES is a tool for MS/PC-DOS 2+ that simplifies the process
- of turning a utility written in C, Pascal or whatever into a
- resident program. It requires a few fixups from the programmer,
- but if you know what you're doing, the extra work is minimal.
-
- What LDRES does
-
- LDRES takes a COM file as input, and tacks a couple of
- modules on the end of it, including an interrupt (9) routine.
- When the modified program is first run, control jumps to an
- initialization module that sets up the interrupt routine and
- leaves the program memory-resident. As expected by COM files,
- the interrupt routine sets all segment registers to the CS value
- before passing control to your program. On return, all registers
- are restored and an IRET is executed.
-
- The command-line "m" switch allows you to specify the
- additional memory needed for stack & heap functions (and to avoid
- "insufficient memory" errors at run-time). The memory is added
- below the interrupt routine; you must request enough to make sure
- this routine is not overwritten by your compiler's initialization
- procedures. The default is 100h bytes for a minimal stack; on
- program entry the stack pointer is set to the top of this area,
- just below the interrupt routine. (Fourteen bytes are added to
- this figure by registers pushed by the interrupt routine.) Don't
- forget that even if your program doesn't use the stack, one is
- needed for the interrupts that will occur during its execution.
-
- So that your program can check to see if it is already
- memory-resident (and not load a second time), LDRES sets up a
- dummy interrupt address into which it places the first two
- letters of the filename. The default setting for this is int
- 7eh; it can be changed by using the "i" switch.
-
- LDRES allows you to remove your program from memory when
- already resident by entering "fn /r" on the DOS command line.
- This should generally only be done if your program is the last
- loaded, since interrupt 9 control is passed back to the preceding
- program.
-
- LDRES returns to you with a "program return address" which
- you should note down. You then patch the exit function(s) of your
- program to JMP to this address, and presto, your program has been
- converted into a memory-resident utility that will be invoked
- whenever a certain key combination is pressed.
-
- HOWEVER...
-
- You may have to make a few other changes. The following
- refers to my own experience with the Lattice C compiler (v3.1);
- other compilers may pose other problems.
-
- 1. For one thing, you can't use standard DOS input/output
- functions. You'll have to write assembly-language routines using
- interrupts 16h and 10h. Writing to the screen buffer is easy
- enough, but getting input forces you to do your own editing. I
- won't go into the matters of windows, saving the user's screen,
- etc. Some other DOS functions won't work either; it took me
- several days to discover that the innocent-appearing function 30h
- (Get DOS version) sends memory-resident programs out to lunch.
-
- 2. You will have to disable the memory-management function
- of your compiler that wants to return all extra memory to DOS
- when your program runs. The program doesn't know about the
- interrupt routine sitting on top of it. Since your program is
- already resident, i.e., uses a fixed memory space, the simplest
- thing is just to kill (NOP out) such functions. Look out for DOS
- function 4Ah (or maybe 49h) here.
-
- 3. Compilers expect your program to run once and then return
- to DOS. You may have to reinitialize data areas that are changed
- by the program, or better still, find a way of keeping them
- unchanged. Routines to get the environment or command-line
- parameters are unnecessary in a resident program--if you need to
- look at the environment, it's better to see a fresh copy.
- Lattice C kindly gives you the source for their initialization
- module (C.ASM), so it's not too hard to modify it for this
- purpose; most languages build this function directly into the
- compiler, so you may have to patch your COM file.
-
- If you write in C, be sure to end your program with _exit(),
- not exit(). The latter closes all file handles, including
- standard input & output, expecting DOS to reopen them. This
- would be disastrous if you ran your memory-resident program from
- within another application. Of course the _exit() function must
- be patched with a JMP to the program return address in place of
- its return to DOS. The _tinymain() function will do this for
- you, while saving time by not opening stdin, stderr and the like.
-
- Running LDRES
-
- Format: ldres [\path\]fn.com [/snn /cnn /inn /mnnnn /wblabl]
-
- The switches may be used in any order (enter all numbers in HEX):
-
- /snn = BIOS shift byte value. The program default for this byte
- is 8, meaning that the Alt key is pressed. The shift byte is
- located at 0000:0417h. If you don't have documentation, XRAY.COM
- will display these values on your screen.
-
- /cnn = scan code. This is for the key you press along with the
- shift(s). The default is 35h, or 53, the "/" key. (Be careful
- not to enter the scan code in decimal.)
-
- /inn = dummy interrupt number. This comes set to 7eh, and can be
- changed to anything you like; just be sure not to use an active
- interrupt.
-
- /mnnnn = additional bytes of memory. Unless you are converting a
- small assembly-language program, you should go beyond the default
- of 100h (=256 bytes); the minimal figure for Lattice C is around
- 500h = 1280 bytes.
-
- /wblabla = message to be added to the filename on loading. This
- is a string of ASCII characters (no cr's, linefeeds, tabs) up to
- a maximum of 47. The string must be terminated by a '$'. When
- your program is loaded into memory, it will output "Installing
- fn.com[your message]<CR>". Be sure to include a space if you want
- one after the filename. If you want the filename in capital
- letters, enter it that way on the LDRES command line.
-
- A Sample Session with LDRES
-
- This recounts my experience in creating MCALC.COM, the
- program for which I wrote LDRES in the first place.
-
- 1. Write the higher-level program (e.g. in C), being sure
- to get the I/O right. Use _TINYMAIN, and exit with _exit().
-
- 2. Fix up the load module C.ASM to eliminate: (a) the
- rbrk() memory-management routine (function 4A); (b) the
- environment/command-line routines; (c) sticky calls, like
- function 30 mentioned above.
-
- 3. Compile & link using the modified load module (I called
- this CRES.OBJ).
-
- 4. Run LDRES with the COM file and the appropriate
- parameters.
-
- 5. Using a debugger, kill all remaining troublesome
- functions and set a JMP at exit to the "program return address"
- output by LDRES.
-
- 6. Put the program name in your AUTOEXEC file, reset the
- computer and pray.
-
- 7. Here you have the advantage over me of not having to look
- for bugs in LDRES if something goes wrong. If your program hangs
- the computer, the problem is probably in items (1) or (2), so
- loop until done.
-
- A final word of advice; try out LDRES first on an
- short experimental program to learn what tricks you'll have to
- play on your compiler in order to turn its product into a memory-
- resident application. Good luck, and keep your finger near the
- big red switch!